/*
 * Copyright (c) 2013. wyouflf (wyouflf@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dh.superxz_bottom.xutils.view;

import java.lang.annotation.Annotation;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;

import android.view.View;

import com.dh.superxz_bottom.framework.log.L;
import com.dh.superxz_bottom.xutils.view.annotation.event.EventBase;

public class EventListenerManager {

	private EventListenerManager() {
	}

	/**
	 * k1: viewInjectInfo k2: interface Type value: listener
	 */
	private final static DoubleKeyValueMap<ViewInjectInfo, Class<?>, Object> listenerCache = new DoubleKeyValueMap<ViewInjectInfo, Class<?>, Object>();

	public static void addEventMethod(ViewFinder finder, ViewInjectInfo info,
			Annotation eventAnnotation, Object handler, Method method) {
		try {
			View view = finder.findViewByInfo(info);
			if (view != null) {
				EventBase eventBase = eventAnnotation.annotationType()
						.getAnnotation(EventBase.class);
				Class<?> listenerType = eventBase.listenerType();
				String listenerSetter = eventBase.listenerSetter();
				String methodName = eventBase.methodName();

				boolean addNewMethod = false;
				Object listener = listenerCache.get(info, listenerType);
				DynamicHandler dynamicHandler = null;
				if (listener != null) {
					dynamicHandler = (DynamicHandler) Proxy
							.getInvocationHandler(listener);
					addNewMethod = handler.equals(dynamicHandler.getHandler());
					if (addNewMethod) {
						dynamicHandler.addMethod(methodName, method);
					}
				}
				if (!addNewMethod) {
					dynamicHandler = new DynamicHandler(handler);
					dynamicHandler.addMethod(methodName, method);
					listener = Proxy.newProxyInstance(
							listenerType.getClassLoader(),
							new Class<?>[] { listenerType }, dynamicHandler);

					listenerCache.put(info, listenerType, listener);
				}

				Method setEventListenerMethod = view.getClass().getMethod(
						listenerSetter, listenerType);
				setEventListenerMethod.invoke(view, listener);
			}
		} catch (Throwable e) {
			L.e(e.getMessage(), e.getMessage());
		}
	}

	public static class DynamicHandler implements InvocationHandler {
		private WeakReference<Object> handlerRef;
		private final HashMap<String, Method> methodMap = new HashMap<String, Method>(
				1);

		public DynamicHandler(Object handler) {
			this.handlerRef = new WeakReference<Object>(handler);
		}

		public void addMethod(String name, Method method) {
			methodMap.put(name, method);
		}

		public Object getHandler() {
			return handlerRef.get();
		}

		public void setHandler(Object handler) {
			this.handlerRef = new WeakReference<Object>(handler);
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			Object handler = handlerRef.get();
			if (handler != null) {
				String methodName = method.getName();
				method = methodMap.get(methodName);
				if (method != null) {
					return method.invoke(handler, args);
				}
			}
			return null;
		}
	}
}
